package cz.muni.fi.xvano1.trinity.beans;

import cz.muni.fi.xvano1.trinity.core.Core;
import cz.muni.fi.xvano1.trinity.core.SecondaryParser;
import cz.muni.fi.xvano1.trinity.supplementary.ActionManagerBeanContext;
import cz.muni.fi.xvano1.trinity.supplementary.DataSupplier;
import cz.muni.fi.xvano1.trinity.data.Event;
import cz.muni.fi.xvano1.trinity.data.LicenseRequest;
import cz.muni.fi.xvano1.trinity.supplementary.CalendarHandler;
import java.io.*;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.sourceforge.stripes.action.ActionBean;
import net.sourceforge.stripes.action.ActionBeanContext;
import net.sourceforge.stripes.action.DefaultHandler;
import net.sourceforge.stripes.action.ForwardResolution;
import net.sourceforge.stripes.action.RedirectResolution;
import net.sourceforge.stripes.action.Resolution;
import net.sourceforge.stripes.validation.Validate;
import net.sourceforge.stripes.validation.ValidateNestedProperties;

/**
 * Class implements methods of adding reservation (event) into the system. Due
 * to the framework nature, getter and setter methods for parameters of request
 * have been implemented
 *
 * @author Jan Vano
 */
public class AddEventActionBean implements ActionBean {

    private ActionManagerBeanContext context;
    private String summary;
    private String start;
    private String end;
    private String recurrence;
    private boolean wholeDay;
    private String description;
    private String location;
    private String response;
    private String descriptionOut;
    private String newLine = "<br/>";

    /**
     * Interface method from ActionBean.
     */
    @Override
    public void setContext(ActionBeanContext context) {
        this.context = (ActionManagerBeanContext) context;
    }

    /**
     * Interface method from ActionBean, using a co-variant return type.
     */
    @Override
    public ActionManagerBeanContext getContext() {
        return this.context;
    }

    public String getSummary() {
        return summary;
    }

    public void setSummary(String summary) {
        this.summary = summary;
    }

    public String getStart() {
        return start;
    }

    public void setStart(String start) {
        this.start = start;
    }

    public String getEnd() {
        return end;
    }

    public void setEnd(String end) {
        this.end = end;
    }

    public String getRecurrence() {
        return recurrence;
    }

    public void setRecurrence(String recurrence) {
        this.recurrence = recurrence;
    }

    public boolean getWholeDay() {
        return wholeDay;
    }

    public void setWholeDay(boolean wholeDay) {
        this.wholeDay = wholeDay;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

    public String getDescriptionOut() {
        return descriptionOut;
    }

    public void setDescriptionOut(String descriptionOut) {
        this.descriptionOut = descriptionOut;
    }

    /**
     * Method translates string interpretation of recurrence to integer as
     * specified in the Core class.
     *
     * @param recurrence Recurrence string
     * @return Recurrence integer interpretation
     */
    private int parseRecurrence(String recurrence) {
        if ("NONE".equals(recurrence)) {
            return Core.NONE;
        }
        if ("DAILY".equals(recurrence)) {
            return Core.DAILY;
        }
        if ("WEEKLY".equals(recurrence)) {
            return Core.WEEKLY;
        }
        if ("MONTHLY".equals(recurrence)) {
            return Core.MONTHLY;
        }
        return 0;
    }

    /**
     * Method redirect user to homepage.
     *
     * @return Resolution object to framework
     */
    @DefaultHandler
    public Resolution home() {
        return new RedirectResolution("/Home");
    }

    /**
     * Forwards request to confirmation page. On the confirmation page all the
     * input is interpreted in its final form.
     *
     * @return Resolution to framework with necessary data
     */
    public Resolution addDataConfirm() {
        String validationState = "";
        int totalLicenses = 0;
        getContext().getRequest().setAttribute("summary", summary);
        getContext().getRequest().setAttribute("start", start);
        getContext().getRequest().setAttribute("end", end);
        getContext().getRequest().setAttribute("recurrence", recurrence);
        getContext().getRequest().setAttribute("wholeDay", wholeDay);
        getContext().getRequest().setAttribute("location", location);
        getContext().getRequest().setAttribute("response", response);
        getContext().getRequest().setAttribute("action", "addDataConfirm");

        List<String> toolboxNames = (List<String>) getContext().getServletContext().getAttribute("allowedKeys");
        LicenseRequest request = new LicenseRequest();
        for (String name : toolboxNames) {
            String count = (String) getContext().getRequest().getParameter(name);
            int number = 0;
            try {
                number = Integer.parseInt(count);
            } catch (java.lang.NumberFormatException ex) {
            }
            request.setLicense(name, number);
            totalLicenses += number;
        }
        String requestString = request.generateString();
        String requestOutputString = requestString.replace("\\,", ", ");
        System.out.println("Setting description to: " + requestOutputString);
        getContext().getRequest().setAttribute("description", requestOutputString);
        int inputStatus = SecondaryParser.checkNameDescLoc(summary, requestOutputString, location);
        if ((inputStatus != 0) || (totalLicenses == 0)) {
            System.out.println(inputStatus);
            if ((inputStatus == 1) || (inputStatus == 4)) {
                validationState += "Wrong event description. Description must start with alphanum"
                        + " char and must not end with space. "
                        + "<br/>Further allowed chars are: '\\(),_' and minimal length is 2 characters."
                        + "<br/>";
            }
            if ((inputStatus == 2) || (inputStatus == 5) || (totalLicenses == 0)) {
                validationState += "No toolboxes selected, please select some." + "<br/>";
            }
            if ((inputStatus == 3) || (inputStatus == 6)) {
                validationState += "System did not manage to find target location. "
                        + "Please contact administrator." + "<br/>";
            }
            getContext().getRequest().setAttribute("notice", validationState);
            getContext().getRequest().setAttribute("action", "add");
        }
        if (wholeDay) {
            inputStatus = SecondaryParser.checkSingleDateTime(start);
            if (inputStatus != 0) {
                validationState += "Wrong time-date format/data. Correct format is DD/MM/YYYY HH:MM"
                        + "<br/> where DD is day, MM month, YYYY year, HH hour and MM minute."
                        + "<br/> Count of character must be exact.<br/>";
                getContext().getRequest().setAttribute("notice", validationState);
                getContext().getRequest().setAttribute("action", "add");
            }
        } else {
            inputStatus = SecondaryParser.checkDateTime(start, end);
            if (inputStatus != 0) {
                validationState += "Wrong time-date format/data. Correct format is DD/MM/YYYY HH:MM"
                        + "<br/> where DD is day, MM month, YYYY year, HH hour and MM minute."
                        + "<br/> Count of character must be exact. Note that event may start/end yesterday"
                        + "<br/>  at earliest and year ahead at latest.<br/>";
                getContext().getRequest().setAttribute("notice", validationState);
                getContext().getRequest().setAttribute("action", "add");
            }
        }
        if (recurrence == null) {
            validationState += "Please select recurrence!<br/>";
            getContext().getRequest().setAttribute("notice", validationState);
            getContext().getRequest().setAttribute("action", "add");
        }
        return new ForwardResolution("/Index");
    }

    /**
     * Forwards request to resolution page. On the resolution user can see
     * whether the action has been completed successfuly. Reason for the action
     * is displayed.
     *
     * @return Resolution to framework with necessary data
     * @throws IOException
     * @throws InterruptedException
     */
    public Resolution addData() throws IOException, InterruptedException {
        System.out.println("Adding with description: " + description);
        String user = getContext().getUser();
        String file = Core.userDirectory + user + ".ics";
        String tmp = Core.userDirectory + user + "_tmp.ics";
        Process p = Runtime.getRuntime().exec("cp " + file + " " + tmp);
        p.waitFor();
        Core core = new Core(user + "_tmp");
        int result;
        boolean error = false;
        try {
            int recurInt = parseRecurrence(recurrence);
            result = core.addEvent(summary, start, end,
                    recurInt, wholeDay, description,
                    location);
            if (result != 0) {
                response = "Request status: FAILED" + newLine;
                error = true;
            } else {
                response = "Request status: Event successfuly added" + newLine;
            }
        } catch (NumberFormatException ex) {
            response = "Request status: FAILED" + newLine
                    + "Year/Month/Day/Recurrence/WholeDay switch"
                    + " has to be a number." + newLine;
            error = true;
        }
        response = response + "Reason: " + core.getLastMessage() + newLine;
        response = response + "The supplied parameters were:" + newLine;
        response = response + "Quick description: " + summary + newLine;
        response = response + "Start of event: " + start + newLine;
        response = response + "End of event:" + end + newLine;
        response = response + "Recurrence: " + recurrence + newLine;
        response = response + "Whole day swich: " + wholeDay + newLine;
        response = response + "Description: " + description + newLine;
        response = response + "Location: " + location + newLine;

        synchronized (getContext().getServletContext().getAttribute("userAccessSync")) {
            String update = Core.scripts + "modifyEvents.php " + tmp;
            Process up = Runtime.getRuntime().exec(update);
            up.waitFor();
            int updateResult = up.exitValue();
            if (updateResult == 0) {
                BufferedReader r = null;
                try {
                    r = new BufferedReader(new FileReader(Core.calendar));
                } catch (FileNotFoundException ex) {
                    Logger.getLogger(CalendarViewActionBean.class.getName()).log(Level.SEVERE, null, ex);
                }
                getContext().getServletContext().setAttribute("calendar", CalendarHandler.getCalendarStructure(r));
                String renameBack = "mv " + tmp + " " + file;
                Process finish = Runtime.getRuntime().exec(renameBack);
                finish.waitFor();
            } else if (updateResult == 2) {
                String[] negResponse = CalendarHandler.getNegativeResponse();
                response = "Event " + negResponse[0] + " with UID" + negResponse[1]
                        + " for " + negResponse[2] + " at " + negResponse[3] + " - " + negResponse[4] + " exceeds limit with his request for " + negResponse[5]
                        + " of " + negResponse[6] + ". " + negResponse[7] + " is in use. " + negResponse[8] + " is limit.";
                error = true;
                String cleanup = "rm " + tmp;
                Process clean = Runtime.getRuntime().exec(cleanup);
                clean.waitFor();
            }

            BufferedReader r = null;
            try {
                r = new BufferedReader(new FileReader(Core.calendar));
            } catch (FileNotFoundException ex) {
                Logger.getLogger(CalendarViewActionBean.class.getName()).log(Level.SEVERE, null, ex);
            }
            if (r != null) {
                getContext().getServletContext().setAttribute("calendar", CalendarHandler.getCalendarStructure(r));
            }
        }
        String noticeOrError = (error ? "error" : "notice");
        getContext().getRequest().setAttribute(noticeOrError, response);
        getContext().getRequest().setAttribute("action", "load");
        List<Event> eventList = DataSupplier.loadEvents(user);
        getContext().getRequest().setAttribute("eventList", eventList);
//        System.out.println("Parameter" + getContext().getRequest().getParameter("descriptionOut"));
//        System.out.println("Attribute" + getContext().getRequest().getAttribute("descriptionOut"));
        return new ForwardResolution("/Index");
    }
}
